﻿//
// © Algobox Ltd - Benn Eichhorn
//
using Algobox.Objects.Finance.Assets.Stock;
using Algobox.Objects.Finance.Orders;
using Algobox.Objects.Finance;

namespace Algobox.Structure.Finance.Strategies.LimitSnatcher
{
    public class LimitSnatchOrder : Algobox.Feeds.Finance.Trading.IOrderEvent
    {
        #region Constructors

        public LimitSnatchOrder(Algobox.Feeds.Finance.Trading.ITradingFeedAdaptor tradingFeed, ISnatched callback)
        {
            _tradingFeed = tradingFeed;
            _callback = callback;

            if (Log.IsInfoEnabled)
                Log.Info("{0}|Limit snatch order handler created", callback.ToString());
        }

        #endregion
//////////////////
        #region Member Variables

        private static readonly NLog.Logger Log = NLog.LogManager.GetCurrentClassLogger();

        private Algobox.Feeds.Finance.Trading.ITradingFeedAdaptor _tradingFeed;

        private readonly object _lock = new object();

        private ISnatched _callback;

        private Order _order;

        #endregion
//////////////////
        #region Properties
        
        #endregion
//////////////////
        #region Functions

        public bool Snatch(string account, StockListing stock, bool isBuy, decimal price, uint quantity, out string message)
        {
            lock (_lock)
            {
                if (_order != null)
                {
                    Log.Info("{0}|Snatch is busy snatching existing order", _callback.ToString());
                    message = "LimitSnatch is busy snatching existing order";
                    return false;
                }


                _order = new Order(account, stock, isBuy, price, quantity, Order.OrderType.Limit, Order.TimeInForce.IOC);

                if (Log.IsInfoEnabled)
                    Log.Info("{0}|Snatch attempting to snatch Order({1})", _callback.ToString(), _order);

                return _tradingFeed.TrySubmitOrder(_order, this, out message);
            }
        }

        public bool Snatch(string account, StockListing stock, bool isBuy, decimal price, uint quantity, Exchanges.Destinations dest, out string message)
        {
            lock (_lock)
            {
                if (_order != null)
                {
                    Log.Info("{0}|Snatch is busy snatching existing order", _callback.ToString());
                    message = "LimitSnatch is busy snatching existing order";
                    return false;
                }
                
                _order = new Order(account, stock, isBuy, price, quantity, Order.OrderType.Limit, Order.TimeInForce.IOC);

                if (Log.IsInfoEnabled)
                    Log.Info("{0}|Snatch attempting to snatch Order({1})", _callback.ToString(), _order);

                return _tradingFeed.TrySubmitOrder(_order, this, dest, out message);
            }
        }

        public void OrderUpdate(Order order, Order.Status state)
        {
            if (Log.IsDebugEnabled)
                Log.Debug("{0}|OrderUpdate recieved order in state {1} Order({1})", _callback.ToString(), state, order.ToString());

            lock (_lock)
            {
                switch (state)
                {
                    // order complete
                    case Order.Status.Filled:
                    case Order.Status.Canceled:
                    case Order.Status.Stopped:
                        _order = null;
                        _callback.OnSnatchComplete(this, order);
                        break;

                    // deal with a reject or cancel the order of a replace reject
                    case Order.Status.Rejected:
                        _order = null;
                        _callback.OnSnatchRejected(this, order);
                        break;
                    // otherwise wait for the correct state
                    default:
                        break;
                }

            } // end lock
        }

        #endregion

    }
}
